package model.genetic.genes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class RandomDnaStrategy implements DnaStrategy {

	private Random random;
	
	public RandomDnaStrategy() {
		random = new Random();
	}
	
	@Override
	public SudokuLineGene createGene(int geneLength, List<FixedValue> fixedValues) {
		Collections.sort(fixedValues, new Comparator<FixedValue>() {
			@Override
			public int compare(FixedValue o1, FixedValue o2) {
				return o1.getIndex() - o2.getIndex();
			}
		});
		
		Iterator<FixedValue> fixedValuesIt = fixedValues.listIterator();
		FixedValue currentFixedValue = fixedValuesIt.hasNext() ? fixedValuesIt.next() : null;
		
		int[] dna = new int[geneLength];
		List<Integer> nonFixedIndices = new ArrayList<Integer>(geneLength - fixedValues.size());
		
		for (int i = 0; i < geneLength; ++i) {
			if (currentFixedValue != null && i == currentFixedValue.getIndex()) {
				dna[i] =currentFixedValue.getValue();
				currentFixedValue = fixedValuesIt.hasNext() ? fixedValuesIt.next() : null;
				
				// duplicate fixed value indexes
				assert(i != currentFixedValue.getIndex());
			} else {
				dna[i] = random.nextInt(geneLength) + 1;
				nonFixedIndices.add(new Integer(i));
			}
		}
		
		return new SudokuLineGene(dna, nonFixedIndices);
	}
	
	@Override
	public void mutate(SudokuLineGene gene) {
		List<Integer> nonFixedIndexes = gene.getNonFixedIndices();
		
		if(!nonFixedIndexes.isEmpty()) {
			int randomNonFixedIndex = nonFixedIndexes.get(random.nextInt(nonFixedIndexes.size())).intValue();
			gene.setValueAt(randomNonFixedIndex, random.nextInt(gene.getLength()) + 1);
		}
	}

}
